﻿#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn  ; Enable warnings to assist with detecting common errors.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.


api := "http://www.tuling123.com/openapi/api"
key := "aeaca4b118ae2d0802a214f5ca6cdaf3"
userid := "666666"
Gui, Add, Edit, x0 y0 w400 h400 ReadOnly vlog
Gui, Add, Edit, x0 y400 w400 h100 vwrite
Gui, Add, Button, x300 y500 w80 h20 gsend Default, 发送
Gui, +hwndmainhwnd
Gui, Show, , 图灵文字测试
return
 
GuiClose:
ExitApp
 
#If WinActive("ahk_id " mainhwnd)
$Enter::
goto, send
return
 
^Enter::
ControlSend, Edit2, {Enter}, ahk_id %mainhwnd%
#if
 
send:
Gui, Submit, NoHide
if write
{
    AddText(write,"我")
    GuiControl, , write, % ""
 
    if A_IsUnicode
    {
        msg := {"key":key,"info":write,"userid":userid}
        json_msg := json_fromobj(msg)
    }
    else
        json_msg := "{""key"":""" key """,""info"":""" write """,""userid"":" userid "}"
    ;AddText(json_msg,"SendJSON")
    ret := HTTPPOST(api, "UTF-8", json_msg)
    ;AddText(ret,"系统")
    if (ret<>-1)
    {
        retobj := json_toobj(ret)
        if (retobj.code="100000") ;文字
            AddText(retobj.text,"图灵")
        else if (retobj.code="200000") ;链接类
            AddText(retobj.text "`n" retobj.url,"图灵")
        else if (retobj.code="302000") ;新闻类
        {
            news := ""
            for k,v in retobj.list
                news .= "【" v.source "】" v.article " " v.detailurl "`n"
            AddText(retobj.text "`n" news,"图灵")
        }
        else if (retobj.code="308000") ;菜谱类
        {
            cb := ""
            for k,v in retobj.list
                cb .= "【" v.name "】" v.info " " v.detailurl "`n"
            AddText(retobj.text "`n" cb,"图灵")
        }
        else
            AddText(retobj.code ":" retobj.text,"图灵")
    }
}
 
 
return
 
AddText(text,person){
    global log, mainhwnd
    GuiControlGet, log
    GuiControl, , log, % log "`n`n" person " (" A_Hour ":" A_Min ":" A_Sec ")`n" text
    ControlFocus, Edit2, ahk_id %mainhwnd%
    ControlSend, Edit1, {PGDN 3}, ahk_id %mainhwnd%
}
 
 
HTTPPOST(url, Encoding = "",postData=""){ ;网址，编码,请求方式，post数据
    hObject:=ComObjCreate("WinHttp.WinHttpRequest.5.1")
 
    Try
    {
        hObject.Open("POST",url,False)
        hObject.SetRequestHeader("Content-Type", "application/json")
        hObject.Send(postData)
    }
    catch e
        return -1
 
    if (Encoding && hObject.ResponseBody)
    {
        oADO := ComObjCreate("adodb.stream")
        oADO.Type := 1
        oADO.Mode := 3
        oADO.Open()
        oADO.Write(hObject.ResponseBody)
        oADO.Position := 0
        oADO.Type := 2
        oADO.Charset := Encoding
        return oADO.ReadText(), oADO.Close()
    }
    return hObject.ResponseText
}

; Copyright 漏 2013 VxE. All rights reserved.

; Serialize an object as JSON-like text OR format a string for inclusion therein.
; NOTE: scientific notation is treated as a string and hexadecimal as a number.
; NOTE: UTF-8 sequences are encoded as-is, NOT as their intended codepoint.
json_fromobj( obj ) {

	If IsObject( obj )
	{
		isarray := 0 ; an empty object could be an array... but it ain't, says I
		for key in obj
			if ( key != ++isarray )
			{
				isarray := 0
				Break
			}

		for key, val in obj
			str .= ( A_Index = 1 ? "" : "," ) ( isarray ? "" : json_fromObj( key ) ":" ) json_fromObj( val )

		return isarray ? "[" str "]" : "{" str "}"
	}
	else if obj IS NUMBER
		return obj
;	else if obj IN null,true,false ; AutoHotkey does not natively distinguish these
;		return obj

	; Encode control characters, starting with backslash.
	StringReplace, obj, obj, \, \\, A
	StringReplace, obj, obj, % Chr(08), \b, A
	StringReplace, obj, obj, % A_Tab, \t, A
	StringReplace, obj, obj, `n, \n, A
	StringReplace, obj, obj, % Chr(12), \f, A
	StringReplace, obj, obj, `r, \r, A
	StringReplace, obj, obj, ", \", A
	StringReplace, obj, obj, /, \/, A
	While RegexMatch( obj, "[^\x20-\x7e]", key )
	{
		str := Asc( key )
		val := "\u" . Chr( ( ( str >> 12 ) & 15 ) + ( ( ( str >> 12 ) & 15 ) < 10 ? 48 : 55 ) )
				. Chr( ( ( str >> 8 ) & 15 ) + ( ( ( str >> 8 ) & 15 ) < 10 ? 48 : 55 ) )
				. Chr( ( ( str >> 4 ) & 15 ) + ( ( ( str >> 4 ) & 15 ) < 10 ? 48 : 55 ) )
				. Chr( ( str & 15 ) + ( ( str & 15 ) < 10 ? 48 : 55 ) )
		StringReplace, obj, obj, % key, % val, A
	}
	return """" obj """"
} ; json_fromobj( obj )

; Copyright 漏 2013 VxE. All rights reserved.

; Uses a two-pass iterative approach to deserialize a json string
json_toobj( str ) {

	  quot := """" ; firmcoded specifically for readability. Hardcode for (minor) performance gain
	, ws := "`t`n`r " Chr(160) ; whitespace plus NBSP. This gets trimmed from the markup
	, obj := {} ; dummy object
	, objs := [] ; stack
	, keys := [] ; stack
	, isarrays := [] ; stack
	, literals := [] ; queue
	, y := nest := 0

; First pass swaps out literal strings so we can parse the markup easily
	StringGetPos, z, str, %quot% ; initial seek
	while !ErrorLevel
	{
		; Look for the non-literal quote that ends this string. Encode literal backslashes as '\u005C' because the
		; '\u..' entities are decoded last and that prevents literal backslashes from borking normal characters
		StringGetPos, x, str, %quot%,, % z + 1
		while !ErrorLevel
		{
			StringMid, key, str, z + 2, x - z - 1
			StringReplace, key, key, \\, \u005C, A
			If SubStr( key, 0 ) != "\"
				Break
			StringGetPos, x, str, %quot%,, % x + 1
		}
	;	StringReplace, str, str, %quot%%t%%quot%, %quot% ; this might corrupt the string
		str := ( z ? SubStr( str, 1, z ) : "" ) quot SubStr( str, x + 2 ) ; this won't

	; Decode entities
		StringReplace, key, key, \%quot%, %quot%, A
		StringReplace, key, key, \b, % Chr(08), A
		StringReplace, key, key, \t, % A_Tab, A
		StringReplace, key, key, \n, `n, A
		StringReplace, key, key, \f, % Chr(12), A
		StringReplace, key, key, \r, `r, A
		StringReplace, key, key, \/, /, A
		while y := InStr( key, "\u", 0, y + 1 )
			if ( A_IsUnicode || Abs( "0x" SubStr( key, y + 2, 4 ) ) < 0x100 )
				key := ( y = 1 ? "" : SubStr( key, 1, y - 1 ) ) Chr( "0x" SubStr( key, y + 2, 4 ) ) SubStr( key, y + 6 )

		literals.insert(key)

		StringGetPos, z, str, %quot%,, % z + 1 ; seek
	}

; Second pass parses the markup and builds the object iteratively, swapping placeholders as they are encountered
	key := isarray := 1

	; The outer loop splits the blob into paths at markers where nest level decreases
	Loop Parse, str, % "]}"
	{
		StringReplace, str, A_LoopField, [, [], A ; mark any array open-brackets

		; This inner loop splits the path into segments at markers that signal nest level increases
		Loop Parse, str, % "[{"
		{
			; The first segment might contain members that belong to the previous object
			; Otherwise, push the previous object and key to their stacks and start a new object
			if ( A_Index != 1 )
			{
				objs.insert( obj )
				isarrays.insert( isarray )
				keys.insert( key )
				obj := {}
				isarray := key := Asc( A_LoopField ) = 93
			}

			; arrrrays are made by pirates and they have index keys
			if ( isarray )
			{
				Loop Parse, A_LoopField, `,, % ws "]"
					if ( A_LoopField != "" )
						obj[key++] := A_LoopField = quot ? literals.remove(1) : A_LoopField
			}
			; otherwise, parse the segment as key/value pairs
			else
			{
				Loop Parse, A_LoopField, `,
					Loop Parse, A_LoopField, :, % ws
						if ( A_Index = 1 )
							key := A_LoopField = quot ? literals.remove(1) : A_LoopField
						else if ( A_Index = 2 && A_LoopField != "" )
							obj[key] := A_LoopField = quot ? literals.remove(1) : A_LoopField
			}
			nest += A_Index > 1
		} ; Loop Parse, str, % "[{"

		If !--nest
			Break

		; Insert the newly closed object into the one on top of the stack, then pop the stack
		pbj := obj
		obj := objs.remove()
		obj[key := keys.remove()] := pbj
		If ( isarray := isarrays.remove() )
			key++

	} ; Loop Parse, str, % "]}"

	Return obj
} ; json_toobj( str )